﻿#region << 版 本 注 释 >>
/*----------------------------------------------------------------
 * 创建者：王明亮
 * 创建时间：2022/8/19 23:24:07
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;


namespace Aliang.Core.Helper.Http
{
    /// <summary>
    /// HttpDldFile 的摘要说明
    /// </summary>
    public class HttpDldFile
    {
        private readonly int _byteSize = 1024;

        /// <summary>
        /// 下载中的后缀，下载完成去掉
        /// </summary>
        private const string Suffix = ".downloading";

        /// <summary>
        /// 下载进度发生变化
        /// </summary>
        public event Action<int> ShowDownloadPercent;

        /// <summary>
        /// Http方式下载文件
        /// </summary>
        /// <param name="url">http地址</param>
        /// <param name="localFile">本地文件</param>
        /// <param name="isForce">强制下载</param>
        /// <returns></returns>
        public DownLoadState DownloadFile(string url, string localFile, bool isForce = false)
        {
            DownLoadState ret = DownLoadState.Success;
            string localFileReal = localFile;
            string localFileName = localFileReal + Suffix;

            try
            {
                long startPosition = 0;
                FileStream writeStream;

                if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(localFileReal))
                    return DownLoadState.UrlError;

                //取得远程文件长度
                long remoteFileLength = GetHttpLength(url);
                if (remoteFileLength == 0)
                    return DownLoadState.FileLengthError;
                var dir = Path.GetDirectoryName(localFileReal);
                if (!Directory.Exists(dir) && dir != null)
                {
                    Directory.CreateDirectory(dir);
                }
                if (File.Exists(localFileReal) && !isForce)
                    return DownLoadState.FileNotFound;

                //判断要下载的文件是否存在
                if (File.Exists(localFileName))
                {
                    writeStream = File.OpenWrite(localFileName);
                    startPosition = writeStream.Length;
                    if (startPosition > remoteFileLength)
                    {
                        writeStream.Close();
                        File.Delete(localFileName);
                        writeStream = new FileStream(localFileName, FileMode.Create);
                    }
                    else if (startPosition == remoteFileLength)
                    {
                        DownloadFileOk(localFileReal, localFileName);
                        writeStream.Close();
                        return DownLoadState.Success;
                    }
                    else
                        writeStream.Seek(startPosition, SeekOrigin.Begin);
                }
                else
                    writeStream = new FileStream(localFileName, FileMode.Create);

                HttpWebRequest req = null;
                HttpWebResponse rsp = null;
                try
                {
                    req = (HttpWebRequest)WebRequest.Create(url);
                    if (startPosition > 0)
                        req.AddRange((int)startPosition);

                    rsp = (HttpWebResponse)req.GetResponse();
                    using (Stream readStream = rsp.GetResponseStream())
                    {
                        byte[] btArray = new byte[_byteSize];
                        long currentPosition = startPosition;
                        int contentSize = 0;
                        while ((contentSize = readStream.Read(btArray, 0, btArray.Length)) > 0)
                        {
                            writeStream.Write(btArray, 0, contentSize);
                            currentPosition += contentSize;

                            ShowDownloadPercent?.Invoke((int)(currentPosition * 100 / remoteFileLength));
                        }
                    }
                }
                catch (Exception ex)
                {
                    ret = DownLoadState.FileStreamError;
                }
                finally
                {
                    writeStream.Close();
                    rsp?.Close();
                    req?.Abort();

                    if (ret == 0)
                        DownloadFileOk(localFileReal, localFileName);
                }
            }
            catch (Exception ex)
            {
                ret = DownLoadState.DownLoadError;
            }

            return ret;
        }

        /// <summary>
        /// 下载完成
        /// </summary>
        private void DownloadFileOk(string localFileReal, string localFileWithSuffix)
        {
            try
            {
                //去掉.downloading后缀
                FileInfo fi = new FileInfo(localFileWithSuffix);
                fi.MoveTo(localFileReal);
            }
            catch (Exception ex)
            {

            }
            finally
            {
                //通知完成
                ShowDownloadPercent?.Invoke(100);
            }
        }

        // 从文件头得到远程文件的长度
        private long GetHttpLength(string url)
        {
            long length = 0;
            HttpWebRequest req = null;
            HttpWebResponse rsp = null;
            try
            {
                req = (HttpWebRequest)WebRequest.Create(url);
                rsp = (HttpWebResponse)req.GetResponse();
                if (rsp.StatusCode == HttpStatusCode.OK)
                    length = rsp.ContentLength;
            }
            catch (Exception ex)
            {

            }
            finally
            {
                rsp?.Close();
                req?.Abort();
            }

            return length;
        }

    }

    /// <summary>
    /// 下载状态
    /// </summary>
    public enum DownLoadState
    {
        /// <summary>
        /// 成功 0
        /// </summary>
        Success = 0,
        /// <summary>
        /// 地址异常 1
        /// </summary>
        UrlError = 1,
        /// <summary>
        /// 文件长度 2
        /// </summary>
        FileLengthError = 2,
        /// <summary>
        /// 文件流异常 3
        /// </summary>
        FileStreamError = 3,
        /// <summary>
        /// 下载错误 4
        /// </summary>
        DownLoadError = 4,
        /// <summary>
        /// 文件不存在 5
        /// </summary>
        FileNotFound = 5
    }
}
